#ifndef BFCP_STACK_HXX
#define BFCP_STACK_HXX

#include "BfcpMessage.hxx"
#include "BfcpSendData.hxx"
#include "rutil/TransportType.hxx"
#include "rutil/Fifo.hxx"
#include "rutil/Data.hxx"
#include <list>

namespace bfcp
{
    class BfcpTransportEventThread;
    class BfcpTransportIf;
    class BfcpStack
    {
    public:
        BfcpStack(resip::FdPollGrp *grp = 0);
        virtual ~BfcpStack();

        void addTransport(resip::TransportType protocol,
                          resip::IpVersion version,
                          const resip::Data& ipInterface,
                          int port);

        int getPort() const;
        const BfcpNetTuple& getTuple() const;

        void process(BfcpTransactionMessage* bfcpMsg);
        void processOngoing(BfcpMessage* msg);

        void send(std::auto_ptr<BfcpSendData> data);

        std::auto_ptr<BfcpMessage> requestHello(const bfcp::BfcpNetTuple& destination,
            unsigned int cid, unsigned short uid);
        std::auto_ptr<BfcpMessage> requestFloorStatus(const bfcp::BfcpNetTuple& destination,
            unsigned int cid, unsigned short uid,
            unsigned short floor_id, unsigned short status);
        std::auto_ptr<BfcpMessage> requestFloorStatus(const bfcp::BfcpNetTuple& destination,
            unsigned int cid, unsigned short uid, unsigned short tid,
            unsigned short floor_id, unsigned short floor_req_id, unsigned short status);
        std::auto_ptr<BfcpMessage> requestFloorRequestStatus(const bfcp::BfcpNetTuple& destination,
            unsigned int cid, unsigned short uid,
            unsigned short floor_id, unsigned short status);
        std::auto_ptr<BfcpMessage> requestFloorRequestStatus(const bfcp::BfcpNetTuple& destination,
            unsigned int cid, unsigned short uid, unsigned short tid,
            unsigned short floor_id, unsigned short floor_req_id, unsigned short status);
        std::auto_ptr<BfcpMessage> requestGoodbye(const bfcp::BfcpNetTuple& destination,
            unsigned int cid, unsigned short uid);
        std::auto_ptr<BfcpMessage> responseError(const bfcp::BfcpMessage* req, unsigned short code, const char* err_info = NULL);
        std::auto_ptr<BfcpMessage> responseHelloAck(const bfcp::BfcpMessage* req);
        std::auto_ptr<BfcpMessage> responseFloorRequestStatus(const bfcp::BfcpMessage* req, unsigned short status);
        std::auto_ptr<BfcpMessage> responseFloorRequestStatus(const bfcp::BfcpMessage* req, unsigned short floor_req_id, unsigned short status);
        std::auto_ptr<BfcpMessage> responseFloorStatusAck(const bfcp::BfcpMessage* req);
        std::auto_ptr<BfcpMessage> responseGoodbyeAck(const bfcp::BfcpMessage* req);

        std::auto_ptr<BfcpMessage> makeResponse(const BfcpMessage* request, int primitive);
        std::auto_ptr<BfcpMessage> makeRequest(const BfcpNetTuple& destination, int primitive, unsigned int cid, unsigned short uid, unsigned short tid);

        typedef HashMap<unsigned short, std::list<BfcpTransactionMessage*> > TransactionMap;
        typedef HashMap<unsigned short, BfcpTransactionMessage*> Transactions;
    protected:
        void runInternal();
        void shutdownInternal();

        void setPollGrp(resip::FdPollGrp *grp);
        void process();

        virtual void processIncoming(BfcpTransactionMessage* msg) {}

        resip::Fifo<BfcpTransactionMessage> mStateMacFifo;

    private:
        resip::FdPollGrp* mPollGrp;
        bool mPollGrpIsMine;
        BfcpTransportIf* mTransport;
        BfcpTransportEventThread* mEventThread;
        bool mInternalThreadsRunning;

        TransactionMap mClientTransactionMap;
        TransactionMap mServerTransactionMap;
        Transactions mTransactions;

        static unsigned short sNextTransactionId;
        static unsigned short sNextFloorRequestId;

        friend class BfcpTransportEventThread;
    };
}

#endif //#ifndef BFCP_STACK_HXX
